package com.eatme.web.security.authentication.wechat.applet.filter;

import com.alibaba.fastjson2.JSON;
import com.eatme.web.security.authentication.wechat.applet.authentication.WechatAppletAuthenticationToken;
import com.eatme.web.security.authentication.wechat.applet.vo.WechatAppletRequest;
import com.eatme.web.util.wechat.WXBaseService;
import com.eatme.web.util.wechat.vo.WxBaseResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;

public class WechatAppletAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private static final Logger LOG = LoggerFactory.getLogger(WechatAppletAuthenticationFilter.class);


    private final ObjectMapper objectMapper;


    private final WXBaseService wxBaseService;




    /**
     * 前端传来的 参数名 - 用于request.getParameter 获取
     */
    private final String DEFAULT_EMAIL_NAME="openid";

    private final String DEFAULT_EMAIL_CODE="code";

    /**
     * 是否 仅仅post方式
     */
    private boolean postOnly = true;

    /**
     * 通过 传入的 参数 创建 匹配器
     * 即 Filter过滤的url
     */
    public WechatAppletAuthenticationFilter(ObjectMapper objectMapper,WXBaseService wxBaseService) {
        super(new AntPathRequestMatcher("/applet/login"));
        this.objectMapper = objectMapper;
        this.wxBaseService = wxBaseService;
    }


    /**
     * filter 获得 用户名（邮箱） 和 密码（验证码） 装配到 token 上 ，
     * 然后把token 交给 provider 进行授权
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
        WechatAppletAuthenticationToken authenticationToken;
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        try (InputStream is = request.getInputStream()) {
            //  在这里取消原有的通过 request parameter 形式获取用户名密码的方法, 替换为 json 数据格式的获取
            WechatAppletRequest authenticationBean = objectMapper.readValue(is, WechatAppletRequest.class);
            // 根据 code 获取 openid
            WxBaseResponse wxBaseResponse = wxBaseService.jscode2session(authenticationBean.getCode());
            LOG.info("jscode2session: {}", JSON.toJSONString(wxBaseResponse));
            response.setHeader(HttpHeaders.SET_COOKIE,String.format("%s %s","session_key",wxBaseResponse.getSession_key()));
            authenticationToken = new WechatAppletAuthenticationToken(wxBaseResponse.getOpenId(),wxBaseResponse.getSession_key());
            LOG.info("appAuthenticationToken: {}", JSON.toJSONString(authenticationToken));
        } catch (IOException e) {
            throw new BadCredentialsException("没有找到用户名或密码参数");
        }
        // Allow subclasses to set the "details" property
        setDetails(request, authenticationToken);
        return this.getAuthenticationManager().authenticate(authenticationToken);
    }

    /**
     * 获取 头部信息 让合适的provider 来验证他
     */
    public void setDetails(HttpServletRequest request , WechatAppletAuthenticationToken token ){
        token.setDetails(this.authenticationDetailsSource.buildDetails(request));
    }

    /**
     * 判断 传来的 验证码信息 以及 session 中的验证码信息
     */
    public boolean checkCode(HttpServletRequest request ){
        String code = request.getParameter(DEFAULT_EMAIL_CODE);
        LOG.info("code**********{}",code);
        // TODO 另外再写一个链接 生成 验证码 那个验证码 在生成的时候  存进redis 中去
        //TODO  这里的验证码 写在Redis中， 到时候取出来判断即可 验证之后 删除验证码
        if(code.equals("123456")){
            return true;
        }
        return false;
    }
	// set、get方法...


}